#region using

using System;
using System.Reflection;
using FluentDBC.Extensions;

#endregion using

namespace FluentDBC.Default
{
    public class ValidationContractEngine<TModel> : IValidationContractEngine<TModel>
    {
        #region private variables, fields, and ctors

        private readonly IFluentDBCConfiguration _codeContractFactory;
        private readonly IFieldContract<TModel> _fieldContract;
        private readonly string _fieldName;
        private readonly bool _precondition;

        public ValidationContractEngine(
            IFluentDBCConfiguration codeContractFactory,
            IFieldContract<TModel> fieldContract,
            string fieldName,
            bool precondition)
        {
            _codeContractFactory = codeContractFactory;
            _fieldContract = fieldContract;
            _fieldName = fieldName;
            _precondition = precondition;
        }

        #endregion private variables, fields, and ctors

        #region api functions

        public IFieldContract<TModel> IsNotNull(string message = "")
        {
            return AllContractActionProcessing(message, MethodBase.GetCurrentMethod().Name);
        }

        public IFieldContract<TModel> IsNotNullOrEmpty(string message = "")
        {
            return AllContractActionProcessing(message, MethodBase.GetCurrentMethod().Name);
        }

        #endregion api functions

        #region private functions

        private IFieldContract<TModel> AllContractActionProcessing(string message, string methodName)
        {
            var typeInstance = GetContractActionType(methodName);

            if (_precondition)
                return ProcessingValidationContract(() => (IValidationContractAction)Activator.CreateInstance(typeInstance, message));
            else
            {
                // TODO implement post condition
                return null;
            }
        }

        private Type GetContractActionType(string methodName)
        {
            var typeInstance = _codeContractFactory.GetContractAction(methodName);

            if (typeInstance == null)
                throw new NullReferenceException(GlobalFluentDBCResources.CannotFindContractActionInCoreSystem);

            return typeInstance;
        }

        private IFieldContract<TModel> ProcessingValidationContract(Func<IValidationContractAction> validationContractFunc)
        {
            foreach (var classContract in _codeContractFactory.ClassContracts)
            {
                foreach (var field in classContract.Fields)
                {
                    if (field.FieldName.CultureEquals(_fieldName))
                    {
                        field.ValidationContractActions.Add(validationContractFunc());
                    }
                }
            }

            return _fieldContract;
        }

        #endregion private functions
    }
}